package ERMDE.models.tests;

import java.util.UUID;

import junit.framework.Assert;
import main.java.ERMDE.infrastructure.Func;
import main.java.ERMDE.infrastructure.IterableExtensions;
import main.java.ERMDE.models.Cardinality;
import main.java.ERMDE.models.Entity;
import main.java.ERMDE.models.Interface;
import main.java.ERMDE.models.Relationship;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public class RelationshipTestCase {
	private Entity firstEntity;
	private Entity secondEntity;
	private Entity thirdEntity;

	@Test
	public void testCreatingRelationshipSetsId() throws Exception {
		Interface relationshipEntity = new Interface(this.firstEntity,
				new Cardinality(0, 1), "");

		Interface relationshipEntity2 = new Interface(this.secondEntity,
				new Cardinality(0, 1), "");

		Relationship relationship = new Relationship(relationshipEntity,
				relationshipEntity2);

		Assert.assertTrue(relationship.getId() instanceof UUID);
		Assert.assertEquals(0, relationship.getAttributes().count());
	}

	@Test
	public void testCanCreateRelationshipWithDifferentEntities()
			throws Exception {
		Interface relationshipEntity = new Interface(this.firstEntity,
				new Cardinality(0, 1), "");

		Interface relationshipEntity2 = new Interface(this.secondEntity,
				new Cardinality(0, 1), "");

		Relationship relationship = new Relationship(relationshipEntity,
				relationshipEntity2);

		Func<Interface, UUID, Boolean> cmpFunc = new Func<Interface, UUID, Boolean>() {
			@Override
			public Boolean execute(Interface relEntity, UUID id) {
				return relEntity.getEntityId() == id;
			}
		};

		Iterable<Interface> relationshipEntities = relationship
				.getRelationshipEntities();
		Assert.assertEquals(2, IterableExtensions.count(relationshipEntities));
		Assert.assertSame(relationshipEntity, IterableExtensions
				.firstOrDefault(relationshipEntities, cmpFunc,
						this.firstEntity.getId()));

		Assert.assertSame(relationshipEntity2, IterableExtensions
				.firstOrDefault(relationshipEntities, cmpFunc,
						this.secondEntity.getId()));
	}

	@Test
	public void testCanCreateRelationshipWithSameEntitiesAndDifferentRoles()
			throws Exception {
		Interface relationshipEntity = new Interface(this.firstEntity,
				new Cardinality(0, 1), "role1");

		Interface relationshipEntity2 = new Interface(this.secondEntity,
				new Cardinality(0, 1), "role2");

		Relationship relationship = new Relationship(relationshipEntity,
				relationshipEntity2);

		Func<Interface, UUID, Boolean> cmpFunc = new Func<Interface, UUID, Boolean>() {
			@Override
			public Boolean execute(Interface relEntity, UUID id) {
				return relEntity.getEntityId() == id;
			}
		};

		Iterable<Interface> relationshipEntities = relationship
				.getRelationshipEntities();
		Assert.assertEquals(2, IterableExtensions.count(relationshipEntities));
		Assert.assertSame(relationshipEntity, IterableExtensions
				.firstOrDefault(relationshipEntities, cmpFunc,
						this.firstEntity.getId()));

		Assert.assertSame(relationshipEntity2, IterableExtensions
				.firstOrDefault(relationshipEntities, cmpFunc,
						this.secondEntity.getId()));
	}

	@Test(expected = Exception.class)
	public void testCreatingRelationshipWithSameEntityTwiceWithoutRoleThrows()
			throws Exception {
		Interface relationshipEntity = new Interface(this.firstEntity,
				new Cardinality(0, 1), "");

		Interface relationshipEntity2 = new Interface(this.firstEntity,
				new Cardinality(0, 1), "role");

		new Relationship(relationshipEntity, relationshipEntity2);
	}

	@Test(expected = Exception.class)
	public void testCreatingRelationshipWithSameEntityTwiceWithSameRoleThrows()
			throws Exception {
		Interface relationshipEntity = new Interface(this.firstEntity,
				new Cardinality(0, 1), "role");

		Interface relationshipEntity2 = new Interface(this.firstEntity,
				new Cardinality(0, 1), "role");

		new Relationship(relationshipEntity, relationshipEntity2);
	}

	@Test
	public void testCanAddRelationshipEntityWithRelatedToDifferentEntity()
			throws Exception {
		Interface relationshipEntity = new Interface(this.firstEntity,
				new Cardinality(0, 1), "");

		Interface relationshipEntity2 = new Interface(this.secondEntity,
				new Cardinality(0, 1), "");

		Interface relationshipEntity3 = new Interface(this.thirdEntity,
				new Cardinality(0, 1), "");

		Relationship relationship = new Relationship(relationshipEntity,
				relationshipEntity2);

		Func<Interface, UUID, Boolean> cmpFunc = new Func<Interface, UUID, Boolean>() {
			@Override
			public Boolean execute(Interface relEntity, UUID id) {
				return relEntity.getEntityId() == id;
			}
		};

		relationship.addRelationshipEntity(relationshipEntity3);

		Iterable<Interface> relationshipEntities = relationship
				.getRelationshipEntities();
		Assert.assertEquals(3, IterableExtensions.count(relationshipEntities));
		Assert.assertSame(relationshipEntity, IterableExtensions
				.firstOrDefault(relationshipEntities, cmpFunc,
						this.firstEntity.getId()));

		Assert.assertSame(relationshipEntity2, IterableExtensions
				.firstOrDefault(relationshipEntities, cmpFunc,
						this.secondEntity.getId()));

		Assert.assertSame(relationshipEntity3, IterableExtensions
				.firstOrDefault(relationshipEntities, cmpFunc,
						this.thirdEntity.getId()));
	}

	@Test
	public void testCanNotAddRelationshipWithSameEntityWithoutRoleInFirstOne()
			throws Exception {
		Interface relationshipEntity = new Interface(this.firstEntity,
				new Cardinality(0, 1), "");

		Interface relationshipEntity2 = new Interface(this.secondEntity,
				new Cardinality(0, 1), "");

		Interface relationshipEntity3 = new Interface(this.firstEntity,
				new Cardinality(0, 1), "role");

		Relationship relationship = new Relationship(relationshipEntity,
				relationshipEntity2);
		Assert.assertFalse(relationship
				.addRelationshipEntity(relationshipEntity3));
	}

	@Test
	public void testCanNotAddRelationshipWithSameEntityWithoutRoleInSecondOne()
			throws Exception {
		Interface relationshipEntity = new Interface(this.firstEntity,
				new Cardinality(0, 1), "role");

		Interface relationshipEntity2 = new Interface(this.secondEntity,
				new Cardinality(0, 1), "");

		Interface relationshipEntity3 = new Interface(this.firstEntity,
				new Cardinality(0, 1), "");

		Relationship relationship = new Relationship(relationshipEntity,
				relationshipEntity2);
		Assert.assertFalse(relationship
				.addRelationshipEntity(relationshipEntity3));
	}

	@Test
	public void testCanNotAddRelationshipWithSameEntityWithSameRole()
			throws Exception {
		Interface relationshipEntity = new Interface(this.firstEntity,
				new Cardinality(0, 1), "role");

		Interface relationshipEntity2 = new Interface(this.secondEntity,
				new Cardinality(0, 1), "");

		Interface relationshipEntity3 = new Interface(this.firstEntity,
				new Cardinality(0, 1), "role");

		Relationship relationship = new Relationship(relationshipEntity,
				relationshipEntity2);
		Assert.assertFalse(relationship
				.addRelationshipEntity(relationshipEntity3));
	}

	@Test
	public void testCanAddRelationshipWithSameEntityWithoutRoleInSecondOne()
			throws Exception {
		Interface relationshipEntity = new Interface(this.firstEntity,
				new Cardinality(0, 1), "role");

		Interface relationshipEntity2 = new Interface(this.secondEntity,
				new Cardinality(0, 1), "");

		Interface relationshipEntity3 = new Interface(this.firstEntity,
				new Cardinality(0, 1), "role2");

		Relationship relationship = new Relationship(relationshipEntity,
				relationshipEntity2);
		Assert.assertTrue(relationship
				.addRelationshipEntity(relationshipEntity3));
		Assert.assertEquals(3, IterableExtensions.count(relationship
				.getRelationshipEntities()));
	}

	@Before
	public void setUp() throws Exception {
		this.firstEntity = new Entity("RelatedEntity1");
		this.secondEntity = new Entity("RelatedEntity2");
		this.thirdEntity = new Entity("RelatedEntity3");
	}

	@After
	public void tearDown() throws Exception {
	}
}